/**
 * Copyright (c) 2022 KCloud-Platform-Alibaba Authors. All Rights Reserved.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 *   http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.laokou.common.elasticsearch.template;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.DynamicMapping;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import co.elastic.clients.util.ObjectBuilder;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.laokou.common.elasticsearch.constant.EsConstant;
import org.laokou.common.elasticsearch.utils.FieldMapping;
import org.laokou.common.elasticsearch.utils.FieldMappingUtil;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @author laokou
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class NewElasticsearchTemplate {

    private final ElasticsearchClient elasticsearchClient;

    private static final String PRIMARY_KEY_NAME = "id";

    private static final String HIGHLIGHT_PRE_TAGS = "<span style='color:red;'>";

    private static final String HIGHLIGHT_POST_TAGS = "</span>";

//    /**
//     * 批量同步数据到ES
//     * @param indexName    索引名称
//     * @param jsonDataList 数据列表
//     * @throws IOException IOException
//     */
//    public Boolean syncBatchIndex(String indexName, String jsonDataList) throws IOException {
//        // 判空
//        if (EmptyUtil.isEmpty(jsonDataList)) {
//            log.error("数据为空，无法批量同步数据");
//            return false;
//        }
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，批量同步失败",indexName);
//            return false;
//        }
//        // 批量操作Request
//        BulkRequest bulkRequest = packBulkIndexRequest(indexName, jsonDataList);
//        if (bulkRequest.requests().isEmpty()) {
//            log.error("组件的数据为空，无法批量同步数据");
//            return false;
//        }
//        final BulkResponse bulk = elasticsearchClient.bulk(bulkRequest);
//        if (bulk.hasFailures()) {
//            for (BulkItemResponse item : bulk.getItems()) {
//                log.error("索引[{}],主键[{}]更新操作失败，状态为:[{}],错误信息:{}",indexName,item.getId(),item.status(),item.getFailureMessage());
//            }
//            return false;
//        }
//        // 记录索引新增与修改数量
//        Integer createdCount = 0;
//        Integer updatedCount = 0;
//        for (BulkItemResponse item : bulk.getItems()) {
//            if (DocWriteResponse.Result.CREATED.equals(item.getResponse().getResult())) {
//                createdCount++;
//            } else if (DocWriteResponse.Result.UPDATED.equals(item.getResponse().getResult())){
//                updatedCount++;
//            }
//        }
//        log.info("索引[{}]批量同步更新成功，共新增[{}]个，修改[{}]个",indexName,createdCount,updatedCount);
//        return true;
//    }
//
//    /**
//     * 批量修改ES
//     * @param indexName    索引名称
//     * @param jsonDataList 数据列表
//     * @param clazz        类型
//     */
//    public Boolean updateBatchIndex(String indexName, String jsonDataList, Class<?> clazz) {
//        //判空
//        if (EmptyUtil.isEmpty(jsonDataList)) {
//            log.error("数据为空，无法批量修改数据");
//            return false;
//        }
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，批量修改失败",indexName);
//            return false;
//        }
//        BulkRequest bulkRequest = packBulkUpdateRequest(indexName, jsonDataList);
//        if (bulkRequest.requests().isEmpty()) {
//            log.error("组件的数据为空，无法批量修改数据");
//            return false;
//        }
//        try {
//            //同步执行
//            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
//            if (bulk.hasFailures()) {
//                for (BulkItemResponse item : bulk.getItems()) {
//                    log.error("索引【{}】,主键[{}]修改操作失败，状态为【{}】,错误信息：{}",indexName,item.getId(),item.status(),item.getFailureMessage());
//                }
//                return false;
//            }
//            //记录索引新增与修改数量
//            Integer createCount = 0;
//            Integer updateCount = 0;
//            for (BulkItemResponse item : bulk.getItems()) {
//                if (DocWriteResponse.Result.CREATED.equals(item.getResponse().getResult())) {
//                    createCount++;
//                } else if (DocWriteResponse.Result.UPDATED.equals(item.getResponse().getResult())) {
//                    updateCount++;
//                }
//            }
//            log.info("索引【{}】批量修改更新成功，共新增[{}]个，修改[{}]个",indexName,createCount,updateCount);
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.error("索引【{}】批量修改更新出现异常",indexName);
//            return false;
//        }
//        return true;
//    }
//
//    /**
//     * ES修改数据
//     * @param indexName 索引名称
//     * @param id        主键
//     * @param paramJson 参数JSON
//     */
//    public Boolean updateIndex(String indexName, String id, String paramJson) {
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，修改失败",indexName);
//            return false;
//        }
//        UpdateRequest updateRequest = new UpdateRequest(indexName, id);
//        //如果修改索引中不存在则进行新增
//        updateRequest.docAsUpsert(true);
//        //立即刷新数据
//        updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
//        updateRequest.doc(paramJson,XContentType.JSON);
//        try {
//            UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
//            log.info("索引[{}]主键【{}】，操作结果:[{}]",indexName,id,updateResponse.getResult());
//            if (DocWriteResponse.Result.CREATED.equals(updateResponse.getResult())) {
//                //新增
//                log.info("索引【{}】主键【{}】，新增成功",indexName,id);
//            } else if (DocWriteResponse.Result.UPDATED.equals(updateResponse.getResult())) {
//                //修改
//                log.info("索引【{}】主键【{}】，修改成功",indexName, id);
//            } else if (DocWriteResponse.Result.NOOP.equals(updateResponse.getResult())) {
//                //无变化
//                log.info("索引[{}]主键[{}]，无变化",indexName, id);
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.error("索引[{}]主键【{}】，更新异常:[{}]",indexName, id,e);
//        }
//        return true;
//    }
//
//    /**
//     * 删除数据
//     * @param indexName 索引名称
//     * @param id        主键
//     * @return Boolean
//     */
//    public Boolean deleteById(String indexName, String id) {
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，删除失败",indexName);
//            return false;
//        }
//        DeleteRequest deleteRequest = new DeleteRequest(indexName);
//        deleteRequest.id(id);
//        deleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
//        try {
//            DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
//            if (DocWriteResponse.Result.NOT_FOUND.equals(deleteResponse.getResult())) {
//                log.error("索引【{}】主键【{}】删除失败",indexName, id);
//            } else {
//                log.info("索引【{}】主键【{}】删除成功",indexName, id);
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.error("删除索引【{}】出现异常[{}]",indexName,e);
//        }
//        return true;
//    }
//
//    /**
//     * 批量删除ES
//     * @param indexName 索引名称
//     * @param ids       id列表
//     * @return Boolean
//     */
//    public Boolean deleteBatchIndex(String indexName, List<String> ids) {
//        if (EmptyUtil.isEmpty(ids)) {
//            log.error("ids为空，不能批量删除数据");
//            return false;
//        }
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，批量删除失败",indexName);
//            return false;
//        }
//        BulkRequest bulkRequest = packBulkDeleteRequest(indexName, ids);
//        try {
//            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
//            if (bulk.hasFailures()) {
//                for (BulkItemResponse item : bulk.getItems()) {
//                    log.error("删除索引:[{}],主键：{}失败，信息：{}",indexName,item.getId(),item.getFailureMessage());
//                }
//                return false;
//            }
//            // 记录索引新增与修改数量
//            Integer deleteCount = 0;
//            for (BulkItemResponse item : bulk.getItems()) {
//                if (DocWriteResponse.Result.DELETED.equals(item.getResponse().getResult())) {
//                    deleteCount++;
//                }
//            }
//            log.info("批量删除索引[{}]成功，共删除[{}]个",indexName,deleteCount);
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.error("删除索引：【{}】出现异常:{}",indexName,e);
//        }
//        return true;
//    }
//
//    /**
//     * 组装删除操作
//     * @param indexName 索引名称
//     * @param ids id列表
//     * @return BulkRequest
//     */
//    private BulkRequest packBulkDeleteRequest(String indexName, List<String> ids) {
//        BulkRequest bulkRequest = new BulkRequest();
//        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
//        ids.forEach(id -> {
//            DeleteRequest deleteRequest = new DeleteRequest(indexName);
//            deleteRequest.id(id);
//            bulkRequest.add(deleteRequest);
//        });
//        return bulkRequest;
//    }
//
//    /**
//     * 组装bulkUpdate
//     * @param indexName 索引名称
//     * @param jsonDataList 数据列表
//     * @return BulkRequest
//     */
//    private BulkRequest packBulkUpdateRequest(String indexName,String jsonDataList) {
//        BulkRequest bulkRequest = new BulkRequest();
//        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
//        List<Object> jsonList = JacksonUtil.toList(jsonDataList, Object.class);
//        if (jsonList.isEmpty()) {
//            return bulkRequest;
//        }
//        // 循环数据封装bulkRequest
//        jsonList.forEach(obj ->{
//            Map<String, Object> map = (Map<String, Object>) obj;
//            UpdateRequest updateRequest = new UpdateRequest(indexName,map.get(PRIMARY_KEY_NAME).toString());
//            // 修改索引中不存在就新增
//            updateRequest.docAsUpsert(true);
//            updateRequest.doc(JacksonUtil.toJsonStr(obj), XContentType.JSON);
//            bulkRequest.add(updateRequest);
//        });
//        return bulkRequest;
//    }
//
//    /**
//     * 根据主键查询ES
//     * @param indexName 索引名称
//     * @param id 主键
//     * @return String
//     */
//    public String getIndexById(String indexName,String id) {
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，查询失败",indexName);
//            return null;
//        }
//        GetRequest getRequest = new GetRequest(indexName, id);
//        try {
//            GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
//            String resultJson = getResponse.getSourceAsString();
//            log.info("索引【{}】主键【{}】，查询结果：【{}】",indexName,id,resultJson);
//            return resultJson;
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.error("索引【{}】主键[{}]，查询异常：{}",indexName,id,e);
//            return null;
//        }
//    }
//
//    /**
//     * 清空内容
//     * @param indexName 索引名称
//     */
//    public Boolean deleteAll(String indexName) {
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，删除失败",indexName);
//            return false;
//        }
//        DeleteRequest deleteRequest = new DeleteRequest(indexName);
//        deleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
//        try {
//            DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
//            if (DocWriteResponse.Result.NOT_FOUND.equals(deleteResponse.getResult())) {
//                log.error("索引【{}】删除失败",indexName);
//                return false;
//            }
//            log.info("索引【{}】删除成功",indexName);
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.error("删除索引[{}]，出现异常[{}]",indexName,e);
//        }
//        return true;
//    }
//
//    /**
//     * 批量数据保存到ES-异步
//     * @param indexName    索引名称
//     * @param jsonDataList 数据列表
//     */
//    public void syncAsyncBatchIndex(String indexName, String jsonDataList) {
//        // 判空
//        if (EmptyUtil.isEmpty(jsonDataList)) {
//            log.error("数据为空，无法批量异步同步数据");
//            return;
//        }
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，批量异步同步失败",indexName);
//            return;
//        }
//        // 批量操作Request
//        BulkRequest bulkRequest = packBulkIndexRequest(indexName, jsonDataList);
//        if (bulkRequest.requests().isEmpty()) {
//            log.error("组装数据为空，无法批量异步同步数据");
//            return;
//        }
//        // 异步执行
//        ActionListener<BulkResponse> listener = new ActionListener<>() {
//            @Override
//            public void onResponse(BulkResponse bulkItemResponses) {
//                if (bulkItemResponses.hasFailures()) {
//                    for (BulkItemResponse item : bulkItemResponses.getItems()) {
//                        log.error("索引【{}】,主键【{}】更新失败，状态【{}】，错误信息：{}", indexName, item.getId(),
//                                item.status(), item.getFailureMessage());
//                    }
//                }
//            }
//
//            // 失败操作
//            @Override
//            public void onFailure(Exception e) {
//                log.error("索引【{}】批量异步更新出现异常:{}", indexName, e);
//            }
//        };
//        restHighLevelClient.bulkAsync(bulkRequest,RequestOptions.DEFAULT,listener);
//        log.info("索引批量更新索引【{}】中",indexName);
//    }
//
//    /**
//     * 删除索引
//     * @param indexName 索引名称
//     * @return Boolean
//     * @throws IOException IOException
//     */
//    public Boolean deleteIndex(String indexName) throws IOException {
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，删除失败",indexName);
//            return false;
//        }
//        // 删除操作Request
//        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
//        deleteIndexRequest.indicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);
//        AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
//        if (!acknowledgedResponse.isAcknowledged()) {
//            log.error("索引【{}】删除失败",indexName);
//            return false;
//        }
//        log.info("索引【{}】删除成功",indexName);
//        return true;
//    }
//
//    /**
//     * 异步删除索引
//     * @param indexName 索引名称
//     */
//    public void deleteAsyncIndex(String indexName) {
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，异步删除失败",indexName);
//            return;
//        }
//        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
//        deleteIndexRequest.indicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);
//        ActionListener<AcknowledgedResponse> listener = new ActionListener<>() {
//            @Override
//            public void onResponse(AcknowledgedResponse acknowledgedResponse) {
//                if (acknowledgedResponse.isAcknowledged()) {
//                    log.info("索引【{}】删除成功", indexName);
//                } else {
//                    log.error("索引【{}】删除失败", indexName);
//                }
//            }
//
//            @Override
//            public void onFailure(Exception e) {
//                log.error("索引【{}】删除失败，失败信息:{}", indexName, e);
//            }
//        };
//        restHighLevelClient.indices().deleteAsync(deleteIndexRequest,RequestOptions.DEFAULT,listener);
//    }
//    /**
//     * 批量操作的Request
//     * @param indexName 索引名称
//     * @param jsonDataList json数据列表
//     * @return BulkRequest
//     */
//    private BulkRequest packBulkIndexRequest(String indexName,String jsonDataList) {
//        BulkRequest bulkRequest = new BulkRequest();
//        // IMMEDIATE > 请求向es提交数据，立即进行数据刷新<实时性高，资源消耗高>
//        // WAIT_UNTIL >  请求向es提交数据，等待数据完成刷新<实时性高，资源消耗低>
//        // NONE > 默认策略<实时性低>
//        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
//        List<Object> jsonList = JacksonUtil.toList(jsonDataList, Object.class);
//        if (jsonList.isEmpty()) {
//            return bulkRequest;
//        }
//        // 循环数据封装bulkRequest
//        jsonList.forEach(obj ->{
//            Map<String, Object> map = (Map<String, Object>) obj;
//            IndexRequest indexRequest = new IndexRequest(indexName);
//            indexRequest.source(JacksonUtil.toJsonStr(obj),XContentType.JSON);
//            indexRequest.id(map.get(PRIMARY_KEY_NAME).toString());
//            bulkRequest.add(indexRequest);
//        });
//        return bulkRequest;
//    }
//
//
//    /**
//     * 异步创建ES索引
//     * @param indexName 索引名称
//     * @param indexAlias 别名
//     * @param clazz  类型
//     * @throws IOException IOException
//     */
//    public void createAsyncIndex(String indexName,String indexAlias, Class<?> clazz) throws IOException {
//        boolean indexExists = isIndexExists(indexName);
//        if (indexExists) {
//            log.error("索引【{}】已存在，异步创建失败",indexName);
//            return;
//        }
//        CreateIndexRequest createIndexRequest = getCreateIndexRequest(indexName, indexAlias, FieldMappingUtil.getFieldInfo(clazz));
//        // 异步方式创建索引
//        ActionListener<CreateIndexResponse> listener = new ActionListener<>() {
//            @Override
//            public void onResponse(CreateIndexResponse createIndexResponse) {
//                boolean acknowledged = createIndexResponse.isAcknowledged();
//                if (acknowledged) {
//                    log.info("索引【{}】创建成功", indexName);
//                } else {
//                    log.error("索引【{}】创建失败", indexName);
//                }
//            }
//            @Override
//            public void onFailure(Exception e) {
//                log.error("索引【{}】创建失败，错误信息:{}", indexName, e);
//            }
//        };
//        // 异步执行
//        restHighLevelClient.indices().createAsync(createIndexRequest, RequestOptions.DEFAULT, listener);
//    }
//
//    private CreateIndexRequest getCreateIndexRequest(String indexName, String indexAlias, List<FieldMapping> fieldMappingList) throws IOException {
//        // 封装es索引的mapping
//        XContentBuilder mapping = packEsMapping(fieldMappingList);
//        mapping.endObject().endObject();
//        mapping.close();
//        // 索引创建
//        CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
//        // 配置分词器
//        XContentBuilder settings = packSettingMapping();
//        // 别名
//        XContentBuilder aliases = packEsAliases(indexAlias);
//        createIndexRequest.settings(settings);
//        createIndexRequest.mapping(mapping);
//        createIndexRequest.aliases(aliases);
//        return createIndexRequest;
//    }
//
//    /**
//     * 数据同步到ES
//     * @param id        主键
//     * @param indexName 索引名称
//     * @param jsonData  json数据
//     */
//    public Boolean syncIndex(String id, String indexName, String jsonData) throws IOException {
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，同步失败",indexName);
//            return false;
//        }
//        // 创建操作Request
//        IndexRequest indexRequest = new IndexRequest(indexName);
//        // 配置相关信息
//        indexRequest.source(jsonData, XContentType.JSON);
//        // IMMEDIATE > 立即刷新
//        indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
//        indexRequest.id(id);
//        IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
//        // 判断索引是新增还是修改
//        if (IndexResponse.Result.CREATED.equals(response.getResult())) {
//            log.info("索引【{}】保存成功",indexName);
//        } else if (IndexResponse.Result.UPDATED.equals(response.getResult())) {
//            log.info("索引【{}】修改成功",indexName);
//        }
//        return true;
//    }
//
//    /**
//     * 异步同步
//     * @param id 编号
//     * @param indexName 索引名称
//     * @param jsonData 数据
//     */
//    public void syncIndexAsync(String id, String indexName, String jsonData) {
//        // 判断索引是否存在
//        boolean indexExists = isIndexExists(indexName);
//        if (!indexExists) {
//            log.error("索引【{}】不存在，异步同步失败",indexName);
//            return;
//        }
//        // 创建操作Request
//        IndexRequest indexRequest = new IndexRequest(indexName);
//        // 配置相关信息
//        indexRequest.source(jsonData, XContentType.JSON);
//        // IMMEDIATE > 立即刷新
//        indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
//        indexRequest.id(id);
//        ActionListener<IndexResponse> actionListener = new ActionListener<>() {
//            @Override
//            public void onResponse(IndexResponse indexResponse) {
//                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
//                    log.info("索引【{}】异步同步成功", indexName);
//                } else {
//                    log.error("索引【{}】异步同步失败", indexName);
//                }
//            }
//
//            @Override
//            public void onFailure(Exception e) {
//                log.error("索引【{}】异步同步出现异常:{}", indexName, e);
//            }
//        };
//        restHighLevelClient.indexAsync(indexRequest, RequestOptions.DEFAULT, actionListener);
//    }

    /**
     * 索引是否存在
     * @param indexNames 索引集合名称
     * @return boolean
     */
    public boolean isIndexExists(List<String> indexNames) {
        try {
            ExistsRequest existsRequest = ExistsRequest.of(exists -> exists.index(indexNames));
            return elasticsearchClient.indices().exists(existsRequest).value();
        }catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 索引是否存在
     * @param indexName 索引名称
     * @return boolean
     */
    public boolean isIndexExists(String indexName) {
        return isIndexExists(List.of(indexName));
    }

    /**
     * <a href="https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/8.6/package-structure.html">...</a>
     * 创建ES索引
     * @param indexName 索引名称
     */
    @SneakyThrows
    public <TDocument> void createIndex(String indexName,String indexAlias,Class<TDocument> clazz) {
        // 判断索引是否存在
        boolean indexExists = isIndexExists(indexName);
        if (indexExists) {
            log.error("索引【{}】已存在，创建失败",indexName);
            return;
        }
        elasticsearchClient.indices().create(request -> request.index(indexName)
                .aliases(indexAlias, fn -> fn.isWriteIndex(true))
                .mappings(getMapping(clazz))
        );
    }

    private <TDocument> TypeMapping getMapping(Class<TDocument> clazz) {
        List<FieldMapping> fieldInfo = FieldMappingUtil.getFieldInfo(clazz);
        TypeMapping.Builder builder = new TypeMapping.Builder();
        builder.dynamic(DynamicMapping.True);
        fieldInfo.forEach(item -> properties(builder,item));
        return builder.build();
    }

    private void properties(TypeMapping.Builder builder,FieldMapping mapping) {
        String field = mapping.getField();
        String type = mapping.getType();
        Integer participle = mapping.getParticiple();
        if (EsConstant.IK_INDEX.equals(participle)) {
            builder.properties(field, fn -> fn.text(t -> t.searchAnalyzer("ik_smart").analyzer("ik_max_word")));
        } else {
            builder.properties(field, fn -> fn.keyword(k -> k));
        }
    }

//    /**
//     * 创建索引设置相关配置信息
//     * @param indexName 索引名称
//     * @param indexAlias 索引别名
//     * @param fieldMappingList 数据列表
//     * @return Boolean
//     * @throws IOException IOException
//     */
//    private Boolean createIndexAndCreateMapping(String indexName,String indexAlias, List<FieldMapping> fieldMappingList) throws IOException {
//        // 封装es索引的mapping
//        CreateIndexRequest createIndexRequest = getCreateIndexRequest(indexName, indexAlias, fieldMappingList);
//        // 同步方式创建索引
//        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
//        boolean acknowledged = createIndexResponse.isAcknowledged();
//        if (acknowledged) {
//            log.info("索引:{}创建成功", indexName);
//            return true;
//        } else {
//            log.error("索引:{}创建失败", indexName);
//            return false;
//        }
//    }
//
//    /**
//     * 配置ES别名
//     * @author laokou
//     * @param alias 别名
//     * @return XContentBuilder
//     * @throws IOException IOException
//     */
//    private XContentBuilder packEsAliases(String alias) throws IOException{
//        XContentBuilder aliases = XContentFactory.jsonBuilder().startObject()
//                .startObject(alias)
//                .field("is_write_index",false)
//                .endObject();
//        aliases.endObject();
//        aliases.close();
//        return aliases;
//    }
//
//    /**
//     * 配置Mapping
//     * @param fieldMappingList 组装的实体类信息
//     * @return XContentBuilder
//     * @throws IOException IOException
//     */
//    private XContentBuilder packEsMapping(List<FieldMapping> fieldMappingList) throws IOException {
//        XContentBuilder mapping = XContentFactory.jsonBuilder().startObject()
//                .field("dynamic",true)
//                .startObject("properties");
//        // 循环实体对象的类型集合封装ES的Mapping
//        for (FieldMapping fieldMapping : fieldMappingList) {
//            String field = fieldMapping.getField();
//            String dataType = fieldMapping.getType();
//            Integer participle = fieldMapping.getParticiple();
//            // 设置分词规则
//            if (EsConstant.NOT_ANALYZED.equals(participle)) {
//                if ("date".equals(dataType)) {
//                    mapping.startObject(field)
//                            .field("type", dataType)
//                            .field("format","yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
//                            .endObject();
//                } else {
//                    mapping.startObject(field)
//                            .field("type", dataType)
//                            .endObject();
//                }
//            } else if (EsConstant.IK_INDEX.equals(participle)) {
//                mapping.startObject(field)
//                        .field("type",dataType)
//                        .field("eager_global_ordinals",true)
//                        // fielddata=true 用来解决text字段不能进行聚合操作
//                        .field("fielddata",true)
//                        .field("analyzer","ik_pinyin")
//                        .field("search_analyzer","ik_max_word")
//                        .endObject();
//            }
//        }
//        return mapping;
//    }
//
//    /**
//     * 配置Settings
//     * @return XContentBuilder
//     * @throws IOException IOException
//     */
//    private XContentBuilder packSettingMapping() throws IOException {
//        XContentBuilder setting = XContentFactory.jsonBuilder().startObject()
//                .startObject("index")
//                .field("number_of_shards",1)
//                .field("number_of_replicas",1)
//                .field("refresh_interval","30s")
//                .startObject("analysis");
//        // ik分词拼音
//        setting.startObject("analyzer")
//                .startObject("ik_pinyin")
//                .field("tokenizer","ik_max_word")
//                .field("filter", "laokou_pinyin")
//                .endObject();
//        setting.endObject();
//        // 设置拼音分词器分词
//        setting.startObject("filter")
//                .startObject("laokou_pinyin")
//                .field("type", "pinyin")
//                // 不会这样划分：刘德华 > [liu,de,hua]
//                .field("keep_full_pinyin", false)
//                // 这样划分：刘德华 > [liudehua]
//                .field("keep_joined_full_pinyin",true)
//                // 保留原始中文
//                .field("keep_original", true)
//                .field("limit_first_letter_length", 16)
//                .field("remove_duplicated_term", true)
//                .field("none_chinese_pinyin_tokenize", false)
//                .endObject()
//                .endObject();
//        setting.endObject().endObject().endObject();
//        setting.close();
//        return setting;
//    }
//
//    /**
//     * 关键字高亮显示
//     * @param searchQo 查询实体类
//     * @return SearchVO
//     */
//    public SearchVO<Map<String,Object>> highlightSearchIndex(SearchQo searchQo) {
//        try {
//            final String[] indexNames = searchQo.getIndexNames();
//            // 用于搜索文档，聚合，定制查询有关操作
//            SearchRequest searchRequest = new SearchRequest();
//            searchRequest.indices(indexNames);
//            searchRequest.source(buildSearchSource(searchQo,true,null));
//            SearchHits hits = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT).getHits();
//            List<Map<String,Object>> data = new ArrayList<>();
//            for (SearchHit hit : hits){
//                Map<String,Object> sourceData = hit.getSourceAsMap();
//                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
//                for (String key : highlightFields.keySet()){
//                    sourceData.put(key,highlightFields.get(key).getFragments()[0].string());
//                }
//                data.add(sourceData);
//            }
//            SearchVO<Map<String,Object>> vo = new SearchVO<>();
//            final long total = hits.getTotalHits().value;
//            vo.setRecords(data);
//            vo.setTotal(total);
//            vo.setPageNum(searchQo.getPageNum());
//            vo.setPageSize(searchQo.getPageSize());
//            return vo;
//        } catch (Exception e) {
//            throw new CustomException("搜索失败");
//        }
//    }
//
//    /**
//     * 构建query
//     * @param searchQo 查询参数
//     * @return BoolQueryBuilder
//     */
//    private BoolQueryBuilder buildBoolQuery(SearchQo searchQo) {
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        // 分词查询
//        final List<SearchDTO> queryStringList = searchQo.getQueryStringList();
//        // or查询
//        final List<SearchDTO> orSearchList = searchQo.getOrSearchList();
//        if (EmptyUtil.isNotEmpty(orSearchList)) {
//            // or查询
//            BoolQueryBuilder orQuery = QueryBuilders.boolQuery();
//            for (SearchDTO dto : orSearchList) {
//                orQuery.should(QueryBuilders.termQuery(dto.getField(), dto.getValue()));
//            }
//            boolQueryBuilder.must(orQuery);
//        }
//        if (EmptyUtil.isNotEmpty(queryStringList)) {
//            // 分词查询
//            BoolQueryBuilder analysisQuery = QueryBuilders.boolQuery();
//            for (SearchDTO dto : queryStringList) {
//                final String field = dto.getField();
//                // 清除左右空格并处理特殊字符
//                final String keyword = QueryParser.escape(dto.getValue().trim());
//                analysisQuery.should(QueryBuilders.queryStringQuery(keyword).field(field));
//            }
//            boolQueryBuilder.must(analysisQuery);
//        }
//        return boolQueryBuilder;
//    }
//
//    /**
//     * 构建搜索
//     * @param searchQo 查询参数
//     * @param isHighlightSearchFlag 是否高亮搜索
//     * @param aggregationBuilder 聚合参数
//     * @return SearchSourceBuilder
//     */
//    private SearchSourceBuilder buildSearchSource(SearchQo searchQo, boolean isHighlightSearchFlag, TermsAggregationBuilder aggregationBuilder) {
//        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        final Integer pageNum = searchQo.getPageNum();
//        final Integer pageSize = searchQo.getPageSize();
//        final List<SearchDTO> sortFieldList = searchQo.getSortFieldList();
//        if (isHighlightSearchFlag) {
//            final List<String> highlightFieldList = searchQo.getHighlightFieldList();
//            // 高亮显示数据
//            HighlightBuilder highlightBuilder = new HighlightBuilder();
//            // 设置关键字显示颜色
//            highlightBuilder.preTags(HIGHLIGHT_PRE_TAGS);
//            highlightBuilder.postTags(HIGHLIGHT_POST_TAGS);
//            //设置显示的关键字
//            for (String field : highlightFieldList) {
//                highlightBuilder.field(field, 0, 0);
//            }
//            // 多个字段高亮,这项要为false
//            highlightBuilder.requireFieldMatch(false);
//            // 设置高亮
//            searchSourceBuilder.highlighter(highlightBuilder);
//        }
//        // 分页
//        if (searchQo.isNeedPage()) {
//            final int pageIndex = (pageNum - 1) * pageSize;
//            searchSourceBuilder.from(pageIndex);
//            searchSourceBuilder.size(pageSize);
//        }
//        // 追踪分数开启
//        searchSourceBuilder.trackScores(true);
//        // 注解
//        searchSourceBuilder.explain(true);
//        // 匹配度倒排，数值越大匹配度越高
//        searchSourceBuilder.sort("_score",SortOrder.DESC);
//        // 排序
//        if (EmptyUtil.isNotEmpty(sortFieldList)) {
//            for (SearchDTO dto : sortFieldList) {
//                SortOrder sortOrder;
//                final String desc = "desc";
//                final String value = dto.getValue();
//                final String field = dto.getField();
//                if (desc.equalsIgnoreCase(value)) {
//                    sortOrder = SortOrder.DESC;
//                } else {
//                    sortOrder = SortOrder.ASC;
//                }
//                searchSourceBuilder.sort(field, sortOrder);
//            }
//        }
//        searchSourceBuilder.query(buildBoolQuery(searchQo));
//        //获取真实总数
//        searchSourceBuilder.trackTotalHits(true);
//        //聚合对象
//        if (null != aggregationBuilder) {
//            searchSourceBuilder.aggregation(aggregationBuilder);
//        }
//        return searchSourceBuilder;
//    }
//
//    /**
//     * 聚合查询
//     * @param searchQo 搜索
//     * @return SearchVO
//     * @throws IOException IOException
//     */
//    public SearchVO<Map<String,Long>> aggregationSearchIndex(SearchQo searchQo) throws IOException {
//        SearchVO<Map<String,Long>> vo = new SearchVO();
//        List<Map<String,Long>> list = new ArrayList<>(5);
//        String[] indexNames = searchQo.getIndexNames();
//        AggregationDTO aggregationKey = searchQo.getAggregationKey();
//        String field = aggregationKey.getField();
//        String groupKey = aggregationKey.getGroupKey();
//        String script = aggregationKey.getScript();
//        TermsAggregationBuilder aggregationBuilder;
//        if (EmptyUtil.isNotEmpty(field)) {
//            aggregationBuilder = AggregationBuilders.terms(groupKey).field(field).size(100000);
//        } else {
//            aggregationBuilder = AggregationBuilders.terms(groupKey).script(new Script(script)).size(100000);
//        }
//        // 用于搜索文档，聚合，定制查询有关操作
//        SearchRequest searchRequest = new SearchRequest();
//        searchRequest.indices(indexNames);
//        searchRequest.source(buildSearchSource(searchQo, false, aggregationBuilder));
//        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//        Aggregations aggregations = searchResponse.getAggregations();
//        Terms aggregation = aggregations.get(groupKey);
//        List<? extends Terms.Bucket> buckets = aggregation.getBuckets();
//        for (Terms.Bucket bucket : buckets) {
//            Map<String,Long> dataMap = new HashMap<>(1);
//            dataMap.put(bucket.getKeyAsString(),bucket.getDocCount());
//            list.add(dataMap);
//        }
//        vo.setRecords(list);
//        vo.setPageNum(searchQo.getPageNum());
//        vo.setPageSize(searchQo.getPageSize());
//        vo.setTotal((long) list.size());
//        return vo;
//    }

}
